using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Collections.Specialized;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Xml;
using System.IO;
using System.Runtime.Serialization;

namespace TST.SharePoint.Shared
{
    /// <summary>
    /// Abstract definition of a datasource.
    /// </summary>
    public abstract class GridDatasource : IIdentifiable<string>
    {
        private string _id;
        private string _name;
        private Fields _fieldList;
        private DatasourceConfiguration _configuration;
        private bool _fieldsLoaded;
        public const string DisplayLinkId = "LinkUrl";
        public const string DisplayListLinkId = "LinkUrlList";
        public const string DisplayFolderLinkId = "LinkUrlFolder";
        public const string DisplayWebLinkId = "LinkUrlWeb";
        public const string IDDATASOURCE = "datasource";
        public const string IDDATASOURCECONTENTTYPE = "contenttype";
        public const string IDDATASOURCEFEATURES = "DatasourceListFeatures";
        public const string IDDATASOURCETFS = "TFSWorkItemsDataSource";
        protected System.Collections.Specialized.StringCollection _queryDebug;

        /// <summary>
        /// Constructor.
        /// </summary>
        protected GridDatasource()
        {
            _queryDebug = new StringCollection();
            _id = IDDATASOURCE;
            _fieldList = new Fields();
        }

        /// <summary>
        /// Get or set the Name.
        /// </summary>
        public string Name
        {
            get { if (string.IsNullOrEmpty(_name)) return _id; else return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// Get the list of fields.
        /// </summary>
        public Fields Fields
        {
            get
            {
                // if no fields are loaded, load them.
                if (!_fieldsLoaded)
                {
                    _fieldList.AddRange(LoadFields());
                    _fieldsLoaded = true;
                }
                return _fieldList;
            }
        }

        public System.Collections.Specialized.StringCollection QueryDebug
        {
            get
            {
                return _queryDebug;
            }
        }

        /// <summary>
        ///  Get or set a XML serializable object that contains the configuration of fields etc.
        /// </summary>
        public DatasourceConfiguration Configuration
        {
            get { return _configuration; }
            set {
                if (_configuration != value)
                {
                    _configuration = value;
                    ClearFields();
                    ReadConfiguration(_configuration);
                }
            }
        }

        /// <summary>
        /// LoadFields loads fields from the specific datasource. Must be implemented by
        /// the datasources.
        /// </summary>
        /// <returns></returns>
        protected abstract IEnumerable<Field> LoadFields();

        /// <summary>
        /// Get the data from the datasource. Abstract and must be implemented by the datasources.
        /// </summary>
        /// <returns></returns>
        public abstract DataTable GetData();
        
        #region IIdentifiable<string> Members

        /// <summary>
        /// Get the ID of the datasource.
        /// </summary>
        public string Id
        {
            get { return _id; }
            protected set { _id = value; }
        }

        #endregion

        /// <summary>
        /// Read configuration of custom properties. Implemented by datasources that know what
        /// custom properties to expect in their configuration.
        /// </summary>
        /// <param name="configuration"></param>
        public virtual void ReadConfiguration(DatasourceConfiguration configuration)
        {
        }

        /// <summary>
        /// Return a list of selected fields, based on the selected references.
        /// </summary>
        /// <param name="fieldReferenceList">List containing references to selected fields.</param>
        /// <returns>A list of selected fields.</returns>
        public Fields GetFieldList(FieldReferences fieldReferenceList)
        {
            Fields result = new Fields();
            foreach(FieldReference fieldRef in fieldReferenceList)
            {
                if (Fields.Contains(fieldRef.Id))
                    result.Add(Fields[fieldRef.Id]);
            }
            return result;
        }

        public void ClearFields()
        {
            _queryDebug.Clear();
            _fieldsLoaded = false;
            _fieldList.Clear();
        }

        public static GridDatasource GetDatasource(DatasourceConfiguration configuration)
        {
            GridDatasource result = null;
            switch (configuration.DatasourceID)
            {
                case IDDATASOURCECONTENTTYPE:
                    result = new DatasourceContentType();
                    break;
            }
            return result;
        }
    }

    /// <summary>
    /// General exception specific to datasources.
    /// </summary>
    [Serializable]
    public class DataSourceException : Exception
    {
        public DataSourceException() : base() {}
        public DataSourceException(string message) : base(message) {}
        protected DataSourceException(SerializationInfo info, StreamingContext context) : base(info, context) {}
        public DataSourceException(string message, Exception innerException) : base(message, innerException) { }
    }
}
